# dash.auk
# Tim Menzies
# Sept 10, 2012

@include "globals.awk"
@include "readcsv.awk"
@include "dist.awk"
@include "lib.awk"

function show_Dash(_Dash) {
  return ":enough " enough \
         " :tooMuch " tooMuch \
         " :prune " prune\
         " :reweight " reweight\
         " :sampleth " sampleth
}
function _dash(    _Dash,o) {
  args("-d,data/autompg.csv,-e,4,-t,20,--p,0,"\
       "--r,1,-seed,1,-sample,10",o)
  seed(    o[ "-seed"])
  enough = o[ "-e"]
  tooMuch= o[ "-t"]
  prune  = o["--p"]
  reweight=o["--r"]
  sampleth=o["-sample"]
  dash(o["-d"],_Dash)
}
function dash(f,_Dash,_Rows,n,os,new,row1,rows,ps) {
 # print f,s,show_Dash(_Dash)
  readcsv("cat " f, _Rows)
  projects(_Dash,_Rows,ps,new)
  n=normalize(ps)
  say(":projections " n " " show_Dash(_Dash) Dollar)
  print dumpHeader(n,ps,_Dash,_Rows)
  rows = length(d)
  for(row1=1;row1<=rows;row1++) 
    print dumprow(row1,n,new,ps,_Rows)
}
function showp(p) {
  print p["id"],p["x"]
}
function dumpHeader(n,ps,_Dash,_Rows,     \
                    cols,col,pre,out,sep,p0,p,neww) {
  cols = length(name)
  for (col=1;col<=cols;col++) {
    pre = gp[col] ? "" : "~"
    out = out sep pre name[col]
    sep = ","
  }
  for(p=1;p<=n;p++) {
    neww= reweight ? ps[p]["x"] : 1
    out = out sep  "$_P" ps[p]["id"] "*" \
      sprintf("%6.4f",neww)
    }
  return out
}
function dumprow(row,n,new,ps,_Rows,   cols,col,out,sep,p0,p) {
  cols = length(name)
  for(col=1;col<=cols;col++) {
    out = out sep d[row][col]
    sep = ","
  }
  for(p0=1;p0<=n;p0++) {
    p = ps[p0]["id"] 
    out = out sep sprintf("%6.4f",new[row][p]) 
  }
  return out
}
function projects(_Dash,_Rows,ps,new,	 p,best,tmp) {
  best = 10**32
  p = 1
  while(--tooMuch > 0) {
    tmp = project(_Dash,_Rows,ps,p,new,best)
    if (tmp < best) {
      p++
      best = tmp
      say(" :better " best Dollar)
      if (--enough < 1)   
        return 0
    } else
      delete ps[p] }
}
function normalize(ps,     n,worst,p) {
  n = asort(ps,ps,"xsort")
  worst = ps[n]["x"]
  for(p=n;p>=1;p--) 
    ps[p]["x"] = worst/ps[p]["x"]
 return n
}

function project(_Dash,_Rows,ps,p,new,best, \
                 min,one,two,i,x,y,a,b,c,row,err,m,n,klass,col,newcol) {
  say(".")
  m    = length(all)
  one  = anybut(all)
  two  = anybut(all,one)
  c = dist(one,two,_Rows)
  for(i in all) {
    row = all[i]
    if (row == one ) {
	    a=x=0; b = c
    } else {
	    if (row == two) { 
        a=x=c;  b = 0
	    } else {
        a = dist(row,one,_Rows)
        b = dist(row,two,_Rows)
        x = (a^2+c^2 - b^2)/(2*c + 0.00001);  
	    }}	   
    y = sqrt(abs(a^2 - x^2))
    err += y  
    if (prune) {
      n++
	    if (n > sampleth && n > m/sampleth)
        if (err/n > best)
          return 10^32 }
    # only update after checking for pruning
    new[row][p] = x
    ps[p]["id"]=p
    ps[p]["<"]=one
    ps[p][">"]=two
    ps[p]["c"]=c
    ps[p]["x"] = err/m
    ps[p]["="][i]["x"] = x 
    ps[p]["="][i]["="] = i  
  }
  return err/m
}
# #XXX summing across all
# function knn(row1,ps,_Row,	\
#              klass,p,one,two,n,row2,w,ws,sum) {
#   klass = klass1(gp)
#   for(p in ps) {
#     one = ps[p]["<"]
#     two = ps[p][">"]
#     if (one == row1) continue
#     if (two == row1) continue
#     n    = length(ps[p]["="])
#     row2 = closest(ps,p,one,two,n,_Row)
#     w    = ps[p]["x"]
#     ws  += w
#     sum += w*d[row2][klass]
#   }
#   return sum/(ws + 0.0001)
#   # XXX must esnure at least two projections
# }
# function closest(ps,p,one,two,n,_Row,           \
#                  a,b,c,x,j,k) {   
#   a = dist(row,one,_Row)
#   b = dist(row,two,_Row)
#   c = ps[p]["c"]
#   x = (a^2+c^2 - b^2)/(2*c + 0.00001)
#   j = place(x,ps[p]["="])
#   k = nextdoor(x,j,n,ps[p]["="])
#   return ps[p]["="][k]["="]
# }
# function nextdoor(x,j,n,a,			\
#                   i,k,ix,kx) {
#   if (j == 1) return 2
#   if (j == n) return n - 1
#   i = j - 1
#   k = j + 1
#   ix = abs(x - a[i]["x"])
#   kx = abs(x - a[k]["x"])
#   if (ix < kx) k = i
#   return k
# }

# function place(goal,a,  lo,hi,mid,here) {
#   lo = 1; hi = length(a)
#   while(max >= min) {
#     mid  = int((lo + hi)/2)
#     here = a[mid]["x"]
#     if (here < goal)      lo = mid + 1
#     else if (here > goal) hi = mid - 1
#     else return mid }
# }
# function rnn(id,a,r,    i,j,k,b,n,right,left) {
#     n=asort(a,b,"xsort") 
#     r[2]++
#     r[n-1]++
#     for(j=2;j<n;j++) {
#        i = j-1
#        k = j+1
#        r[k] += 0; r[i] += 0; r[j] += 0
#        left = b[j]["x"] - b[i]["x"]
#        right= b[k]["x"] - b[j]["x"]
#        if      (left > right)  { r[k]++ }
#        else if (left < right)  { r[i]++ }
#        else                    { r[k]++; r[i]++ }
#     }
# }
